package com.hup.joystick.model;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.hup.joystick.constant.DeviceConstant;
import com.hup.joystick.constant.DeviceConstant.ConnectType;
import com.hup.joystick.constant.DeviceKey.NativeKeys;
import com.hup.joystick.constant.DeviceKey.StandardKeys;
import com.hup.utils.commons.TextUtil;
import com.hup.utils.commons.io.BaseConfig;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.nio.charset.StandardCharsets;

/**
 * 手柄配置
 * @author hugan
 * @date 2020/10/19
 */
@Data
@Log4j2
@NoArgsConstructor
@JSONType(orders = {"name", "guid", "connectType", "keyMap"})
public class DeviceConfig implements BaseConfig<DeviceConfig> {
    public static final String EXT = ".device";

    /**
     * 设备名
     */
    public String name;
    /**
     * 如:0x26b96020-0x170-0x11eb-0x80-0x3-0x44-0x45-0x53-0x54-0x0-0x0
     */
    public String guid;
    public ConnectType connectType = ConnectType.X_INPUT;
    /**
     * 按键映射[key=标准按键 {@link StandardKeys},value=设备按键 {@link NativeKeys}]
     */
    public KeyMapConfig keyMap = new KeyMapConfig();

    /**
     * 配置文件全路径,未保存到文件时为空
     */
    @JSONField(serialize = false)
    public String fromFile;
    /**
     * 是否在线
     */
    @JSONField(serialize = false)
    public boolean online;
    /**
     * 加载错误
     */
    @JSONField(serialize = false)
    public Exception err;

    public DeviceConfig(String name, String guid) {
        this.name = name;
        this.guid = guid;
    }

    @Override
    public boolean writeMapNullValue() {
        return true;
    }

    /**
     * @return 配置文件名:直接取guid
     * @apiNote 如果文件路径过长, 可能会有bug?
     */
    @Override
    public String configPath() {
        return fromFile == null ? (Path.getBaseDir() + guid + EXT) : fromFile;
    }

    public void save2() {
        save();
        fromFile = configPath();//首次保存前,fromFile是空的,保存后重新赋值给它
    }

    /**
     * 取guid的前三位
     *
     * @return nullable
     */
    private String getShortGuid() {
        String shortGuid = null;
        if (guid != null) {
            int len = guid.length();
            int foundCount = 0;
            for (int i = 0; i < len; i++) {
                if (guid.charAt(i) == DeviceConstant.GUID_SPLITER) {
                    foundCount++;
                    if (foundCount == 3) {
                        shortGuid = guid.substring(0, i);
                        break;
                    }
                }
            }
        }
        return shortGuid;
    }

    @Override
    public String toString() {
        return "DeviceConfig{" +
                "name='" + name + '\'' +
                ", guid='" + guid + '\'' +
                ", connectType=" + connectType +
                ", keyMap=" + keyMap +
                ", fromFile='" + fromFile + '\'' +
                ", online=" + online +
                '}';
    }

    /**
     * 读取文件,转成配置;
     *
     * @param file 不限制文件名
     * @return nullable-文件不存在
     */
    public static DeviceConfig loadFromFile(File file) {
        if (!file.exists() || file.isDirectory()) return null;
        DeviceConfig res = null;
        try {
            String str = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
            res = JSON.parseObject(str, DeviceConfig.class);
            if (TextUtil.isBlank(res.name) || TextUtil.isBlank(res.guid)) {
                throw new IllegalArgumentException("设备名或guid为空");
            }
        } catch (Exception e) {
            if (res == null) {
                String fileName = file.getName().replace(EXT, "");
                String[] split = fileName.split("_");
                String devName = split[0];
                String guid = null;
                if (split.length >= 2) guid = split[1];
                res = new DeviceConfig(devName, guid);
            }
            res.err = new RuntimeException("配置文件异常:" + "\n"
                    + file.getAbsolutePath() + "\n"
                    + e.getMessage());
        }
        res.fromFile = file.getAbsolutePath();
        return res;
    }
}
